import { LinkedList, Node } from './linked_list'

class DoublyNode extends Node {
  constructor (element) {
    super(element)
    this.prev = null
  }
}

export class DoublyLikedList extends LinkedList {
  tail = null

  append (element) {
    const newNode = new DoublyNode(element)

    if (this.head === null) {
      this.head = newNode
      this.tail = newNode
    } else {
      this.tail.next = newNode
      newNode.prev = this.tail
      this.tail = newNode
    }

    this.length++ 
  }

  insert (position, element) {
    if (position < 0 || position > this.length) return false
    
    const newNode = new DoublyNode(element)

    if (position === 0) {
      if (this.head === null) {
        this.head = newNode
        this.tail = newNode
      } else {
        newNode.next = this.head
        this.head.prev = newNode
        this.head = newNode
      }
    } else if (position === this.length) {
      this.tail.next = newNode
      newNode.prev = this.tail
      this.tail = newNode
    } else {
      let index = 0
      let current = this.head
      let previous = null

      while (index++ < position) {
        previous = current
        current = current.next
      }

      previous.next = newNode
      newNode.prev = previous 
      current.prev = newNode
      newNode.next = current
    }

    this.length++

    return true
  }
  
  removeAt (position) {
    if (position < 0 || position > this.length - 1) return null

    let current = this.head
    if (position === 0) {
      if (this.length === 1) {
        this.head = null
        this.tail = null
      } else {
        this.head = this.head.next
        this.head.prev = null
      }
    } else if (position === this.length - 1) {
      current = this.tail
      this.tail.prev.next = null
      this.tail = this.tail.prev
    } else {
      let index = 0
      let previous = null
      while (index++ < position) {
        previous = current
        current = current.next
      }

      previous.next = current.next
      current.next.prev = previous
    }

    this.length--

    return current.element
  }
}